package gcode

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"lsgfish/server/internal/dto/request"

	"gorm.io/gorm"
)

// Generator 代码生成器接口
type Generator interface {
	// Generate 生成代码，生成文件到磁盘
	Generate() (map[string]string, error)
	// GenerateInMemory 生成代码但不写入磁盘
	GenerateInMemory() (map[string]string, error)
}

// generatorService 代码生成器服务实现
type generatorService struct {
	db           *gorm.DB
	request      request.GenerateCodeRequest
	config       *CodeGenConfig
	tables       map[string]*TableStructure
	tableConfigs map[string]*TableConfig // 表配置映射
}

// NewGenerator 创建新的代码生成器
func NewGenerator(db *gorm.DB, request request.GenerateCodeRequest) Generator {
	return &generatorService{
		db:           db,
		request:      request,
		config:       &Config, // 使用全局配置
		tables:       make(map[string]*TableStructure),
		tableConfigs: make(map[string]*TableConfig),
	}
}

// Generate 生成代码
func (g *generatorService) Generate() (map[string]string, error) {
	// 存储生成的文件内容
	generatedFiles := make(map[string]string)

	fmt.Println("======= 代码生成器配置信息 =======")
	fmt.Printf("包名: %s\n", g.config.PackageName)
	fmt.Printf("模块名: %s\n", g.config.ModuleName)
	fmt.Printf("使用驼峰命名: %v\n", g.config.UseCamelCase)
	fmt.Printf("要处理的表数量: %d\n", len(g.request.Tables))

	// 预处理表信息，添加模型名等配置
	fmt.Println("\n======= 开始预处理表信息 =======")
	if err := g.preprocessTables(); err != nil {
		fmt.Printf("预处理表信息失败: %v\n", err)
		return nil, fmt.Errorf("预处理表信息失败: %w", err)
	}
	fmt.Println("表信息预处理完成")

	// 收集表结构信息
	fmt.Println("\n======= 开始收集表结构信息 =======")
	if err := g.collectTableInfo(); err != nil {
		fmt.Printf("收集表结构信息失败: %v\n", err)
		return nil, fmt.Errorf("收集表结构信息失败: %w", err)
	}
	fmt.Println("表结构信息收集完成")

	// 为每个表生成模型文件
	fmt.Println("\n======= 开始生成模型文件 =======")
	if err := g.generateModels(generatedFiles); err != nil {
		fmt.Printf("生成模型文件失败: %v\n", err)
		return nil, fmt.Errorf("生成模型文件失败: %w", err)
	}
	fmt.Println("模型文件生成完成")

	// 生成仓库层代码
	fmt.Println("\n======= 开始生成仓库层代码 =======")
	if err := g.generateRepositories(generatedFiles); err != nil {
		fmt.Printf("生成仓库层代码失败: %v\n", err)
		return nil, fmt.Errorf("生成仓库层代码失败: %w", err)
	}
	fmt.Println("仓库层代码生成完成")

	// 生成服务层代码
	fmt.Println("\n======= 开始生成服务层代码 =======")
	if err := g.generateServices(generatedFiles); err != nil {
		fmt.Printf("生成服务层代码失败: %v\n", err)
		return nil, fmt.Errorf("生成服务层代码失败: %w", err)
	}
	fmt.Println("服务层代码生成完成")

	// 生成控制器代码
	fmt.Println("\n======= 开始生成控制器代码 =======")
	if err := g.generateControllers(generatedFiles); err != nil {
		fmt.Printf("生成控制器代码失败: %v\n", err)
		return nil, fmt.Errorf("生成控制器代码失败: %w", err)
	}
	fmt.Println("控制器代码生成完成")

	// 生成路由文件
	fmt.Println("\n======= 开始生成路由文件 =======")
	if err := g.generateRouters(generatedFiles); err != nil {
		fmt.Printf("生成路由文件失败: %v\n", err)
		return nil, fmt.Errorf("生成路由文件失败: %w", err)
	}
	fmt.Println("路由文件生成完成")

	// 生成请求DTO文件
	fmt.Println("\n======= 开始生成请求DTO文件 =======")
	if err := g.generateRequestDtos(generatedFiles); err != nil {
		fmt.Printf("生成请求DTO文件失败: %v\n", err)
		return nil, fmt.Errorf("生成请求DTO文件失败: %w", err)
	}
	fmt.Println("请求DTO文件生成完成")

	// 生成响应DTO文件
	fmt.Println("\n======= 开始生成响应DTO文件 =======")
	if err := g.generateResponseDtos(generatedFiles); err != nil {
		fmt.Printf("生成响应DTO文件失败: %v\n", err)
		return nil, fmt.Errorf("生成响应DTO文件失败: %w", err)
	}
	fmt.Println("响应DTO文件生成完成")

	// 将生成的文件写入磁盘
	fmt.Println("\n======= 开始写入文件到磁盘 =======")
	if err := g.writeFilesToDisk(generatedFiles); err != nil {
		fmt.Printf("写入文件到磁盘失败: %v\n", err)
		return nil, fmt.Errorf("写入文件到磁盘失败: %w", err)
	}
	fmt.Printf("文件写入磁盘完成，共写入 %d 个文件\n", len(generatedFiles))

	return generatedFiles, nil
}

// GenerateInMemory 生成代码但不写入磁盘
func (g *generatorService) GenerateInMemory() (map[string]string, error) {
	// 存储生成的文件内容
	generatedFiles := make(map[string]string)

	fmt.Println("======= 代码生成器配置信息 =======")
	fmt.Printf("包名: %s\n", g.config.PackageName)
	fmt.Printf("模块名: %s\n", g.config.ModuleName)
	fmt.Printf("使用驼峰命名: %v\n", g.config.UseCamelCase)
	fmt.Printf("要处理的表数量: %d\n", len(g.request.Tables))

	// 预处理表信息，添加模型名等配置
	fmt.Println("\n======= 开始预处理表信息 =======")
	if err := g.preprocessTables(); err != nil {
		fmt.Printf("预处理表信息失败: %v\n", err)
		return nil, fmt.Errorf("预处理表信息失败: %w", err)
	}
	fmt.Println("表信息预处理完成")

	// 收集表结构信息
	fmt.Println("\n======= 开始收集表结构信息 =======")
	if err := g.collectTableInfo(); err != nil {
		fmt.Printf("收集表结构信息失败: %v\n", err)
		return nil, fmt.Errorf("收集表结构信息失败: %w", err)
	}
	fmt.Println("表结构信息收集完成")

	// 为每个表生成模型文件
	fmt.Println("\n======= 开始生成模型文件 =======")
	if err := g.generateModels(generatedFiles); err != nil {
		fmt.Printf("生成模型文件失败: %v\n", err)
		return nil, fmt.Errorf("生成模型文件失败: %w", err)
	}
	fmt.Println("模型文件生成完成")

	// 生成仓库层代码
	fmt.Println("\n======= 开始生成仓库层代码 =======")
	if err := g.generateRepositories(generatedFiles); err != nil {
		fmt.Printf("生成仓库层代码失败: %v\n", err)
		return nil, fmt.Errorf("生成仓库层代码失败: %w", err)
	}
	fmt.Println("仓库层代码生成完成")

	// 生成服务层代码
	fmt.Println("\n======= 开始生成服务层代码 =======")
	if err := g.generateServices(generatedFiles); err != nil {
		fmt.Printf("生成服务层代码失败: %v\n", err)
		return nil, fmt.Errorf("生成服务层代码失败: %w", err)
	}
	fmt.Println("服务层代码生成完成")

	// 生成控制器代码
	fmt.Println("\n======= 开始生成控制器代码 =======")
	if err := g.generateControllers(generatedFiles); err != nil {
		fmt.Printf("生成控制器代码失败: %v\n", err)
		return nil, fmt.Errorf("生成控制器代码失败: %w", err)
	}
	fmt.Println("控制器代码生成完成")

	// 生成路由文件
	fmt.Println("\n======= 开始生成路由文件 =======")
	if err := g.generateRouters(generatedFiles); err != nil {
		fmt.Printf("生成路由文件失败: %v\n", err)
		return nil, fmt.Errorf("生成路由文件失败: %w", err)
	}
	fmt.Println("路由文件生成完成")

	// 生成请求DTO文件
	fmt.Println("\n======= 开始生成请求DTO文件 =======")
	if err := g.generateRequestDtos(generatedFiles); err != nil {
		fmt.Printf("生成请求DTO文件失败: %v\n", err)
		return nil, fmt.Errorf("生成请求DTO文件失败: %w", err)
	}
	fmt.Println("请求DTO文件生成完成")

	// 生成响应DTO文件
	fmt.Println("\n======= 开始生成响应DTO文件 =======")
	if err := g.generateResponseDtos(generatedFiles); err != nil {
		fmt.Printf("生成响应DTO文件失败: %v\n", err)
		return nil, fmt.Errorf("生成响应DTO文件失败: %w", err)
	}
	fmt.Println("响应DTO文件生成完成")

	fmt.Printf("\n======= 代码生成完成，共生成 %d 个文件 =======\n", len(generatedFiles))

	// 直接返回生成的文件内容，不写入磁盘
	return generatedFiles, nil
}

// preprocessTables 预处理表信息，添加模型名等配置
func (g *generatorService) preprocessTables() error {
	// 增强表信息，填充必要字段
	for i := range g.request.Tables {
		table := g.request.Tables[i]

		// 表名首字母大写作为默认模型名
		tableName := table.TableName
		// 拆分表前缀（如果有的话）
		parts := strings.Split(tableName, "_")
		// 对表名进行处理，每部分首字母大写
		modelName := ""
		for _, part := range parts {
			if part != "" {
				modelName += strings.ToUpper(part[:1])
				if len(part) > 1 {
					modelName += part[1:]
				}
			}
		}

		// 创建表配置
		tableConfig := &TableConfig{
			Database:     table.Database,
			TableName:    table.TableName,
			ModelName:    modelName,
			UseCamelCase: g.config.UseCamelCase,
		}

		// 存储表配置
		g.tableConfigs[table.TableName] = tableConfig
	}

	return nil
}

// collectTableInfo 收集表结构信息
func (g *generatorService) collectTableInfo() error {
	for _, table := range g.request.Tables {
		// 查询表结构
		var tableStructure TableStructure

		// 打印调试信息
		fmt.Printf("开始查询表结构: 数据库=%s, 表名=%s\n", table.Database, table.TableName)

		// 查询表基本信息，使用map接收避免GORM的struct扫描问题
		var tableInfoMap map[string]interface{}
		err := g.db.Raw(`
			SELECT 
				TABLE_NAME as name,
				ENGINE as engine,
				TABLE_COMMENT as comment,
				CREATE_TIME as create_time,
				UPDATE_TIME as update_time
			FROM 
				information_schema.TABLES
			WHERE 
				TABLE_SCHEMA = ? AND TABLE_NAME = ?
		`, table.Database, table.TableName).Take(&tableInfoMap).Error

		if err != nil {
			fmt.Printf("获取表[%s.%s]信息失败: %v\n", table.Database, table.TableName, err)
			return fmt.Errorf("获取表信息失败: %w", err)
		}

		// 检查表基本信息是否正确获取
		if tableInfoMap == nil || tableInfoMap["name"] == nil {
			fmt.Printf("错误: 表[%s.%s]不存在或无法访问\n", table.Database, table.TableName)
			return fmt.Errorf("表[%s.%s]不存在或无法访问", table.Database, table.TableName)
		}

		// 将map中的数据复制到结构体
		tableStructure.Name = fmt.Sprintf("%v", tableInfoMap["name"])
		tableStructure.Engine = fmt.Sprintf("%v", tableInfoMap["engine"])
		tableStructure.Comment = fmt.Sprintf("%v", tableInfoMap["comment"])
		if tableInfoMap["create_time"] != nil {
			tableStructure.CreateTime = fmt.Sprintf("%v", tableInfoMap["create_time"])
		}
		if tableInfoMap["update_time"] != nil {
			tableStructure.UpdateTime = fmt.Sprintf("%v", tableInfoMap["update_time"])
		}

		fmt.Printf("成功获取表基本信息: %s\n", tableStructure.Name)

		// 查询表字段信息
		var columns []ColumnInfo
		err = g.db.Raw(`
			SELECT 
				COLUMN_NAME as name,
				COLUMN_TYPE as type,
				COLUMN_KEY as column_key,
				IS_NULLABLE as is_nullable,
				COLUMN_DEFAULT as default_value,
				EXTRA as column_extra,
				COLUMN_COMMENT as comment
			FROM 
				information_schema.COLUMNS 
			WHERE 
				TABLE_SCHEMA = ? AND TABLE_NAME = ?
			ORDER BY 
				ORDINAL_POSITION
		`, table.Database, table.TableName).Scan(&columns).Error

		if err != nil {
			fmt.Printf("获取表[%s.%s]字段信息失败: %v\n", table.Database, table.TableName, err)
			return fmt.Errorf("获取表字段信息失败: %w", err)
		}

		if len(columns) == 0 {
			fmt.Printf("错误: 表[%s.%s]没有字段\n", table.Database, table.TableName)
			return fmt.Errorf("表[%s.%s]没有字段", table.Database, table.TableName)
		}

		fmt.Printf("成功获取表字段信息: %d 个字段\n", len(columns))

		tableStructure.Columns = columns

		// 查询主键信息
		var primaryKeys []string
		g.db.Raw(`
			SELECT 
				COLUMN_NAME
			FROM 
				information_schema.KEY_COLUMN_USAGE
			WHERE 
				TABLE_SCHEMA = ? AND TABLE_NAME = ? AND CONSTRAINT_NAME = 'PRIMARY'
			ORDER BY 
				ORDINAL_POSITION
		`, table.Database, table.TableName).Scan(&primaryKeys)

		tableStructure.PrimaryKeys = primaryKeys
		fmt.Printf("获取到主键信息: %v\n", primaryKeys)

		// 查询索引信息
		var indexes []IndexInfo
		err = g.db.Raw(`
			SELECT 
				INDEX_NAME as name,
				NON_UNIQUE as non_unique,
				GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) as columns
			FROM 
				information_schema.STATISTICS
			WHERE 
				TABLE_SCHEMA = ? AND TABLE_NAME = ?
			GROUP BY 
				INDEX_NAME, NON_UNIQUE
		`, table.Database, table.TableName).Scan(&indexes).Error

		if err != nil {
			fmt.Printf("获取表[%s.%s]索引信息失败: %v\n", table.Database, table.TableName, err)
			return fmt.Errorf("获取索引信息失败: %w", err)
		}

		fmt.Printf("成功获取表索引信息: %d 个索引\n", len(indexes))

		tableStructure.Indexes = indexes

		// 存储表结构信息
		g.tables[table.TableName] = &tableStructure
		fmt.Printf("表[%s.%s]信息收集完成\n", table.Database, table.TableName)
	}

	return nil
}

// writeFilesToDisk 将生成的文件写入磁盘
func (g *generatorService) writeFilesToDisk(files map[string]string) error {
	for path, content := range files {
		// 创建目录
		dir := filepath.Dir(path)
		if err := os.MkdirAll(dir, 0755); err != nil {
			return fmt.Errorf("创建目录失败 %s: %w", dir, err)
		}

		// 写入文件
		if err := os.WriteFile(path, []byte(content), 0644); err != nil {
			return fmt.Errorf("写入文件失败 %s: %w", path, err)
		}
	}

	return nil
}

// renderTemplate 渲染模板
func (g *generatorService) renderTemplate(tmplContent string, data interface{}) (string, error) {
	tmpl, err := template.New("").Funcs(template.FuncMap{
		"toLower":        strings.ToLower,
		"toUpper":        strings.ToUpper,
		"capitalize":     capitalize,
		"camelCase":      toCamelCase,
		"lowerCamelCase": toLowerCamelCase,
		"snakeCase":      toSnakeCase,
	}).Parse(tmplContent)

	if err != nil {
		return "", fmt.Errorf("解析模板失败: %w", err)
	}

	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, data); err != nil {
		return "", fmt.Errorf("执行模板失败: %w", err)
	}

	return buf.String(), nil
}

// capitalize 首字母大写
func capitalize(s string) string {
	if s == "" {
		return ""
	}
	return strings.ToUpper(s[:1]) + s[1:]
}

// toCamelCase 转换为驼峰命名
func toCamelCase(s string) string {
	s = strings.TrimSpace(s)
	if s == "" {
		return s
	}

	n := strings.Builder{}
	n.Grow(len(s))
	capNext := false
	for i, v := range []byte(s) {
		vIsCap := v >= 'A' && v <= 'Z'
		vIsLow := v >= 'a' && v <= 'z'
		vIsNum := v >= '0' && v <= '9'

		if v == '_' || v == ' ' || v == '-' {
			capNext = true
		} else if vIsNum || (i == 0 && vIsLow) || (capNext && vIsLow) {
			if vIsLow {
				v -= 'a' - 'A'
			}
			n.WriteByte(v)
			capNext = false
		} else if vIsCap || vIsLow {
			n.WriteByte(v)
			capNext = false
		}
	}

	return n.String()
}

// toLowerCamelCase 转换为小驼峰命名（第一个单词首字母小写）
func toLowerCamelCase(s string) string {
	s = strings.TrimSpace(s)
	if s == "" {
		return s
	}

	// 先转为大驼峰
	camel := toCamelCase(s)
	if len(camel) == 0 {
		return camel
	}

	// 将第一个字母转为小写
	return strings.ToLower(camel[:1]) + camel[1:]
}

// toSnakeCase 转换为下划线命名
func toSnakeCase(s string) string {
	s = strings.TrimSpace(s)
	if s == "" {
		return s
	}

	n := strings.Builder{}
	n.Grow(len(s) * 2)
	for i, v := range []byte(s) {
		vIsCap := v >= 'A' && v <= 'Z'
		vIsLow := v >= 'a' && v <= 'z'
		vIsNum := v >= '0' && v <= '9'

		if vIsNum || vIsLow {
			n.WriteByte(v)
			continue
		}

		if vIsCap {
			if i > 0 {
				n.WriteByte('_')
			}
			n.WriteByte(v - 'A' + 'a')
			continue
		}

		n.WriteByte(v)
	}

	return n.String()
}

// sqlTypeToGoType 将SQL类型转换为Go类型
func sqlTypeToGoType(sqlType string) string {
	// 提取基本类型部分（去掉长度等信息）
	baseType := sqlType
	if idx := strings.Index(baseType, "("); idx > 0 {
		baseType = baseType[:idx]
	}

	// 类型映射
	switch strings.ToLower(baseType) {
	case "tinyint":
		if strings.Contains(sqlType, "(1)") {
			return "bool"
		}
		return "int8"
	case "smallint":
		return "int16"
	case "mediumint", "int":
		return "int"
	case "bigint":
		return "int64"
	case "float":
		return "float32"
	case "double", "decimal":
		return "float64"
	case "char", "varchar", "tinytext", "text", "mediumtext", "longtext":
		return "string"
	case "date", "datetime", "timestamp", "time":
		return "time.Time"
	case "json":
		return "string" // 或者可以使用自定义类型如 JSON
	case "blob", "tinyblob", "mediumblob", "longblob":
		return "[]byte"
	default:
		return "string"
	}
}
